#include "CryptoUtil.h"


#include <time.h>
#include <stdlib.h>
#include <string.h>

#include <jwt.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/evp.h>

#include <iomanip>
#include <iostream>
#include <vector>
#include <fstream>

using std::ifstream;

namespace
{

    // 将字节数组转换为十六进制字符串
    static std::string bytesToHex(const unsigned char* bytes, size_t length) {
        std::ostringstream oss{};
        //规定以十六进制输出，并且填充0
        oss << std::hex << std::setfill('0');
        for (size_t i = 0; i < length; ++i) {
            //规定输出宽度为2，不足2位用0填充
            oss << std::setw(2) << static_cast<int>(bytes[i]);
        }
        return oss.str();
    }

    // 生成随机盐值
    static std::vector<unsigned char> generateSalt(size_t saltSize) {
        //创建一个指定大小的容器，用于存储生成的随机数
        std::vector<unsigned char> salt(saltSize);
        //调用RAND_bytes函数生成随机数
        if (RAND_bytes(salt.data(), saltSize) != 1) {
            std::cout << "Failed to generate random salt\n";
            return std::vector<unsigned char>();
        }
        return salt;
    }

    // 使用 EVP 接口计算 SHA3 - 512 哈希
    static std::string sha3_256(const std::vector<unsigned char>& data) {
        //创建一个EVP_MD_CTX结构体，用于存储哈希上下文信息
        EVP_MD_CTX* mdctx{ EVP_MD_CTX_new() };
        if (!mdctx) {
            std::cout << "Failed to create EVP_MD_CTX\n";
            return "";
        }
        //选择使用的哈希算法
        const EVP_MD* md{ EVP_sha3_256() };
        if (!md) {
            EVP_MD_CTX_free(mdctx);
            std::cout << "Failed to select hash algorithm.\n";
            return "";
        }

        //用选择好的哈希哈希算法初始化哈希上下文
        if (!EVP_DigestInit_ex(mdctx, md, nullptr)) {
            EVP_MD_CTX_free(mdctx);
            std::cout << "Failed to initialize digest.\n";
            return "";
        }

        //用需要计算哈希值的数据更新哈希上下文
        if (!EVP_DigestUpdate(mdctx, data.data(), data.size())) {
            EVP_MD_CTX_free(mdctx);
            std::cout << "Failed to update digest\n";
            return "";
        }

        //完成哈希计算
        //创建一个缓冲区，用于存储计算得到的哈希值
        unsigned char hash[EVP_MAX_MD_SIZE];
        //用于存储哈希值的长度
        unsigned int hashLen;
        //用更新好的上下文计算哈希值，并将结果存储到hash中
        if (!EVP_DigestFinal_ex(mdctx, hash, &hashLen)) {
            EVP_MD_CTX_free(mdctx);
            std::cout << "Failed to finalize digest\n";
            return "";
        }

        EVP_MD_CTX_free(mdctx);
        return bytesToHex(hash, hashLen);
    }

}////end of Anonymity namespace 

namespace l

{

    // 计算带盐值的 SHA3 - 256 哈希
    bool CryptoUtil::hashWithSalt(std::string& hashPassword, std::string& salt, const std::string& passWord, size_t saltSize) {
        // 生成随机盐值
        std::vector<unsigned char> tempsalt{ generateSalt(saltSize) };
        if (tempsalt.empty()) {
            std::cout << "Failed to generate random salt\n";
            return false;
        }

        // 将盐值和输入数据拼接
        std::vector<unsigned char> saltedData{ tempsalt };
        saltedData.insert(saltedData.end(), passWord.begin(), passWord.end());

        // 计算哈希
        hashPassword = sha3_256(saltedData);
        if (hashPassword.empty()) {
            std::cout << "Failed to compute hash\n";
            return false;
        }
        // 将盐值转换为十六进制字符串
        salt = bytesToHex(tempsalt.data(), tempsalt.size());

        return true;
    }

    //计算文件的哈希值
    bool CryptoUtil::hashFileContent(std::string& hashResult, const std::string& fileContent) {

        std::vector<unsigned char> fileData;

        fileData.insert(fileData.end(), fileContent.begin(), fileContent.end());

        // 计算哈希
        hashResult = sha3_256(fileData);
        if (hashResult.empty()) {
            std::cerr << "Failed to compute hash\n";
            return false;
        }

        return true;
    }

    // 验证带盐值的哈希
    bool CryptoUtil::verifyHashWithSalt(const std::string& passWord, const std::string& storedHash, const std::string& salt) {
        // 将十六进制字符串形式的盐值转换为字节数组
        std::vector<unsigned char> storedSalt;
        for (size_t i = 0; i < salt.length(); i += 2) {
            std::string byteStr = salt.substr(i, 2);
            unsigned char byte = static_cast<unsigned char>(std::stoi(byteStr, nullptr, 16));
            storedSalt.push_back(byte);
        }

        // 将盐值和输入数据拼接
        std::vector<unsigned char> saltedData{ storedSalt };
        saltedData.insert(saltedData.end(), passWord.begin(), passWord.end());

        // 计算哈希
        std::string computedHash{ sha3_256(saltedData) };

        // 比较计算得到的哈希和存储的哈希是否一致
        return computedHash == storedHash;
    }

    std::string CryptoUtil::generate_jwt_token(const char* secret_key, int validTime)
    {
        jwt_t* jwt;
        jwt_new(&jwt);  // 创建 JWT

        // 设置算法为 HS256
        jwt_set_alg(jwt, JWT_ALG_HS256, (unsigned char*)secret_key, strlen(secret_key));

        // 设置载荷(Payload): 用户自定义数据
        jwt_add_grant_int(jwt, "exp", time(nullptr) + validTime);   // 过期时间 (默认值1小时)

        char* token = jwt_encode_str(jwt);		// token长度是不确定的，100-300字节

        //创建一个string的token
        std::string stoken{ token };

        // 释放资源
        jwt_free(jwt);
        free(token);
        return stoken;
    }

    bool CryptoUtil::verify_jwt(const char* token, const char* secret_key)
    {
        jwt_t* jwt;
        int err = jwt_decode(&jwt, token, (unsigned char*)secret_key, strlen(secret_key));
        if (err) {
            std::cout << "Invalid JWT!" << std::endl;
            jwt_free(jwt);
            return false;
        }

        // 获取 Payload中的有效时间
        time_t validTime = jwt_get_grant_int(jwt, "exp");
        if (validTime >= time(nullptr)) {
            jwt_free(jwt);
            return true;
        }

        jwt_free(jwt);
        return false;

    }

}//end of namespace l